package triFileSystem;

import triStorage.*;
import transaction.*;
import utils.*;

//WPageArray doesn't support multi-access
public class WPageArray implements IWriter{

	protected Inode inode;
	protected TriMMPFile mmpfile;
	protected int pos;
	protected int lastPageId;
	
	public WPageArray(Inode inode, TriMMPFile mmpfile, Transaction tx) {
		this.inode = inode;
		this.mmpfile = mmpfile;
		
		lastPageId = inode.getLastPageId();
		if (lastPageId < 0)
			lastPageId = allocNewPageId(tx);
		pos = mmpfile.readInt(lastPageId, 0);	
	}

	private int allocNewPageId(Transaction tx) {
		int pageId = mmpfile.allocNewPage();
		inode.allocNewPageId(pageId, tx);
		mmpfile.writeInt(pageId, 0, Constants.INT_SIZE, tx);
		
		return pageId;
	}
	
	@Override
	public void appendInt(int value, Transaction tx) {
		/*if (mmpfile.writeInt(lastPageId, pos, value) < 0) {
			lastPageId = allocNewPageId();
			pos = Constants.INT_SIZE;
			mmpfile.writeInt(lastPageId, pos, value);
		}*/
		
		if (mmpfile.appendInt(lastPageId, pos, value, tx) == Constants.W_ERROCODE) {
			lastPageId = allocNewPageId(tx);
			pos = Constants.INT_SIZE;
			mmpfile.appendInt(lastPageId, pos, value, tx);
		}
		
		pos += Constants.INT_SIZE;
		mmpfile.writeInt(lastPageId, 0, pos, tx);
		//System.out.println("write " + value + " on page = " + lastPageId + " with pos = " + (pos - Constants.INT_SIZE));
	}
	
	@Override
	public void appendLong(long value, Transaction tx) {
		/*
		if (mmpfile.writeLong(lastPageId, pos, value) < 0) {
			lastPageId = allocNewPageId();
			pos = Constants.INT_SIZE;
			mmpfile.writeLong(lastPageId, pos, value);
		}
		*/
		if (mmpfile.appendLong(lastPageId, pos, value, tx) == Constants.W_ERROCODE) {
			lastPageId = allocNewPageId(tx);
			pos = Constants.INT_SIZE;
			mmpfile.appendLong(lastPageId, pos, value, tx);
		}
		
		pos += Constants.LONG_SIZE;
		mmpfile.writeInt(lastPageId, 0, pos, tx);
		//System.out.println("write " + value + " on page = " + lastPageId + " with pos = " + (pos - Constants.LONG_SIZE));
	}

	@Override
	public void appendString(String value, Transaction tx) {
		if (value == null) { 
			appendInt(-1, tx);
			return;
		}

		int length = value.length();
		appendInt(length, tx);
		if (length == 0)
			return;
		
		byte[] bytes = new byte[length];
		Converter.String2Bytes(value, bytes, 0);
		
		//start position
		for (int i = 0, count; i < length; ) {
			//count = mmpfile.writeBytes(lastPageId, pos, bytes, i, length - i);
			count = mmpfile.appendBytes(lastPageId, pos, bytes, i, length - i, tx);
			i += count;
			pos += count;
			mmpfile.writeInt(lastPageId, 0, pos, tx);
			if (i < length) {
				lastPageId = allocNewPageId(tx);
				pos = Constants.INT_SIZE;
			}
		}
	}
	
	@Override
	public long getWritePos() {
		return lastPageId * mmpfile.PAGE_SIZE + pos;
	}
	
	@Override
	public void dispose() {
		//do nothing
	}


}
